{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python 面向对象\n",
    "Python从设计之初就已经是一门面向对象的语言，正因为如此，在Python中创建一个类和对象是很容易的。本章节我们将详细介绍Python的面向对象编程。\n",
    "如果你以前没有接触过面向对象的编程语言，那你可能需要先了解一些面向对象语言的一些基本特征，在头脑里头形成一个基本的面向对象的概念，这样有助于你更容易的学习Python的面向对象编程。\n",
    "接下来我们先来简单的了解下面向对象的一些基本特征。\n",
    "面向对象技术简介\n",
    "类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。\n",
    "类变量：类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。\n",
    "数据成员：类变量或者实例变量用于处理类及其实例对象的相关的数据。\n",
    "方法重写：如果从父类继承的方法不能满足子类的需求，可以对其进行改写，这个过程叫方法的覆盖（override），也称为方法的重写。\n",
    "实例变量：定义在方法中的变量，只作用于当前实例的类。\n",
    "继承：即一个派生类（derived class）继承基类（base class）的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如，有这样一个设计：一个Dog类型的对象派生自Animal类，这是模拟\"是一个（is-a）\"关系（例图，Dog是一个Animal）。\n",
    "实例化：创建一个类的实例，类的具体对象。\n",
    "方法：类中定义的函数。\n",
    "对象：通过类定义的数据结构实例。对象包括两个数据成员（类变量和实例变量）和方法。\n",
    "创建类\n",
    "使用 class 语句来创建一个新类，class 之后为类的名称并以冒号结尾:\n",
    "class ClassName:\n",
    "   '类的帮助信息'   #类文档字符串\n",
    "   class_suite  #类体\n",
    "类的帮助信息可以通过ClassName.__doc__查看。\n",
    "class_suite 由类成员，方法，数据属性组成。\n",
    "实例\n",
    "以下是一个简单的 Python 类的例子:\n",
    "实例\n",
    "#!/usr/bin/python\n",
    "# -*- coding: UTF-8 -*-\n",
    " \n",
    "class Employee:\n",
    "   '所有员工的基类'\n",
    "   empCount = 0\n",
    " \n",
    "   def __init__(self, name, salary):\n",
    "      self.name = name\n",
    "      self.salary = salary\n",
    "      Employee.empCount += 1\n",
    "   \n",
    "   def displayCount(self):\n",
    "     print \"Total Employee %d\" % Employee.empCount\n",
    " \n",
    "   def displayEmployee(self):\n",
    "      print \"Name : \", self.name,  \", Salary: \", self.salary\n",
    "empCount 变量是一个类变量，它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用 Employee.empCount 访问。\n",
    "第一种方法__init__()方法是一种特殊的方法，被称为类的构造函数或初始化方法，当创建了这个类的实例时就会调用该方法\n",
    "self 代表类的实例，self 在定义类的方法时是必须有的，虽然在调用时不必传入相应的参数。\n",
    "self代表类的实例，而非类\n",
    "类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。\n",
    "class Test:\n",
    "    def prt(self):\n",
    "        print(self)\n",
    "        print(self.__class__)\n",
    " \n",
    "t = Test()\n",
    "t.prt()\n",
    "以上实例执行结果为：\n",
    "<__main__.Test instance at 0x10d066878>\n",
    "__main__.Test\n",
    "从执行结果可以很明显的看出，self 代表的是类的实例，代表当前对象的地址，而 self.class 则指向类。\n",
    "self 不是 python 关键字，我们把他换成 runoob 也是可以正常执行的:\n",
    "实例\n",
    "class Test:\n",
    "    def prt(runoob):\n",
    "        print(runoob)\n",
    "        print(runoob.__class__)\n",
    " \n",
    "t = Test()\n",
    "t.prt()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 类：面向对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "class people: # 定义个类\n",
    "    '帮助信息：人类类'\n",
    "    number=100 #类变量定义一般来说就是一个常量\n",
    "    def __init__(self,name ,age): #定义构造函数，创建对象时执行，self代表实力对象，没有方法都需要将实例对象传入否则会报错\n",
    "        self.name=name\n",
    "        self.age=age\n",
    "    def display_num(self):\n",
    "        print(\"number:= %d\"%people.number)#成员变量需要\n",
    "    def display_name(self):\n",
    "        print('name:={}'.format(self.name))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'帮助信息：人类类'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "people.__doc__ # 打印帮助信息"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "number:= 100\n"
     ]
    }
   ],
   "source": [
    "p1=people('guochao',123)\n",
    "\n",
    "p2=people('gcc',123)\n",
    "\n",
    "p1.display_num()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "number:= 100\n"
     ]
    }
   ],
   "source": [
    "p1.number=20\n",
    "p1.display_num()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "name:=gcc\n"
     ]
    }
   ],
   "source": [
    "p2.display_name()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "name:=gyg\n"
     ]
    }
   ],
   "source": [
    "p2.name=\"gyg\"\n",
    "p2.display_name()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "del p1.name #删除实例成员变量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'people' object has no attribute 'name'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-17-fb6aaee39d9a>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mp1\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m: 'people' object has no attribute 'name'"
     ]
    }
   ],
   "source": [
    "p1.name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hasattr(p1,'name')#实例中是否存在属性"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hasattr(p1,'age')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "setattr(p1,'sex',1)#设置实例的成员变量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "getattr(p1,'sex')#获取实例成员变量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on built-in function setattr in module builtins:\n",
      "\n",
      "setattr(obj, name, value, /)\n",
      "    Sets the named attribute on the given object to the specified value.\n",
      "    \n",
      "    setattr(x, 'y', v) is equivalent to ``x.y = v''\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(setattr)# 查询某个方法如何使用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 类中常用API"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "mappingproxy({'__dict__': <attribute '__dict__' of 'people' objects>,\n",
       "              '__doc__': '帮助信息：人类类',\n",
       "              '__init__': <function __main__.people.__init__>,\n",
       "              '__module__': '__main__',\n",
       "              '__weakref__': <attribute '__weakref__' of 'people' objects>,\n",
       "              'display_name': <function __main__.people.display_name>,\n",
       "              'display_num': <function __main__.people.display_num>,\n",
       "              'number': 100})"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "people.__doc__#类的帮助信息\n",
    "people.__name__#类的名称\n",
    "people.__module__#类的模块\n",
    "people.__bases__#类的继承\n",
    "people.__dict__#类的字典信息"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 类的继承和多态"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Parent: #父类\n",
    "    number=100\n",
    "    def __init__(self):\n",
    "        print(\"调用父类构造函数\")\n",
    "    def parentM(self):\n",
    "        print(\"调用父类方法\")\n",
    "    def parentSetattr(self,attr):\n",
    "        self.attr=attr\n",
    "    def parentGetattr(self):\n",
    "        print(self.attr)\n",
    "    def newM(selft):\n",
    "        print('打印父类新方法')\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Child (Parent) :#子类继承父类\n",
    "    def __init__(self):\n",
    "        print('调用子类构造函数')\n",
    "    def childM(self):\n",
    "        print('调用子类方法')\n",
    "    def newM(self):\n",
    "        print('重写父类方法')\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "调用子类构造函数\n",
      "调用子类方法\n",
      "重写父类方法\n",
      "1000\n"
     ]
    }
   ],
   "source": [
    "c=Child()#说明实例化的过程只会调用子类构造器\n",
    "c.childM()\n",
    "c.newM()\n",
    "c.parentSetattr(1000)\n",
    "c.parentGetattr()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
